package com.exrobot.module.rbt.dal.redis;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.exrobot.framework.common.util.collection.CollectionUtils;
import com.exrobot.framework.common.util.json.JsonUtils;
import com.exrobot.framework.common.util.object.BeanUtils;
import com.exrobot.module.rbt.dal.dataobject.robottask.RobotTaskDO;
import jakarta.annotation.Resource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Repository;

import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.exrobot.module.rbt.dal.redis.RedisKeyConstants.*;


/**
 * Rbt 任务的 Redis DAO
 *
 * @author wf
 */
@Repository
public class RbtRedisDAO {

    public static final String TASK_NO_PREFIX = "TK";

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    //region 机器人锁错误记录
    public List<Integer> getLockErr(String sn) {
        String redisKey = String.format(RBT_LOCK_ERR,sn);
        List<String> list = stringRedisTemplate.opsForList().range(redisKey, 0, -1);
        if(list == null || list.isEmpty()) {
            return new ArrayList<>();
        }
        return list.stream().map(Integer::valueOf).collect(Collectors.toList());
    }

    public void setLockErr(String sn,Integer... boxSn) {
        if (boxSn == null || boxSn.length == 0) {
            return;
        }
        String redisKey = String.format(RBT_LOCK_ERR, sn);
        List<String> list = Arrays.stream(boxSn).map(String::valueOf).toList();
        stringRedisTemplate.opsForList().rightPushAll(redisKey, list);
        stringRedisTemplate.expire(redisKey, 1, TimeUnit.DAYS);
    }

    public void deleteLockErr(String sn) {
        String redisKey = String.format(RBT_LOCK_ERR,sn);
        stringRedisTemplate.delete(redisKey);
    }

    //endregion

    //region 机器人任务Hash
    /**
     * 向Hash中添加单个字段值
     * @param sn 机器人SN
     * @param field Hash字段名
     * @param value 字段值
     * @return 是否添加成功
     */
    public boolean setRobotTask(String sn, String field, Object value) {
        try {
            String redisKey = formatTaskKey(sn);
            redisTemplate.opsForHash().put(redisKey, field, value);
            redisTemplate.expire(redisKey, 12, TimeUnit.HOURS);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
    /**
     * 获取Hash中指定字段的值
     * @param sn 机器人SN
     * @param field Hash字段名
     * @return 字段值
     */
    public Object getRobotTask(String sn, String field) {
        String redisKey = formatTaskKey(sn);
        return redisTemplate.opsForHash().get(redisKey, field);
    }

    /**
     * 判断Hash中是否存在指定字段
     * @param sn 机器人SN
     * @param field Hash字段名
     * @return 是否存在
     */
    public boolean hasRobotTaskField(String sn, String field) {
        String redisKey = formatTaskKey(sn);
        return redisTemplate.opsForHash().hasKey(redisKey, field);
    }

    /**
     * 删除Hash中的指定字段
     * @param sn 机器人SN
     * @param fields 字段名数组
     * @return 删除的字段数量
     */
    public long deleteRobotTask(String sn, Object... fields) {
        String redisKey = formatTaskKey(sn);
        return redisTemplate.opsForHash().delete(redisKey, fields);
    }
    //endregion


    public List<RobotTaskDO> getWaitTaskList(String sn, String taskType) {
        String redisKey = String.format(RBT_WAIT_TASK_LIST, sn, taskType);
        Long size = redisTemplate.opsForList().size(redisKey);
        if (size == null || size == 0) {
            return new ArrayList<>();
        }
        List<Object> list = redisTemplate.opsForList().range(redisKey, 0, size - 1);
        return CollectionUtils.convertList(list, obj-> BeanUtils.toBean(obj, RobotTaskDO.class));
    }

    public void setWaitTaskList(String sn,String taskTypoe,RobotTaskDO taskDO) {
        if (taskDO == null) {
            return;
        }
        String redisKey = String.format(RBT_WAIT_TASK_LIST, sn,taskTypoe);
        redisTemplate.opsForList().rightPush(redisKey, taskDO);
        redisTemplate.expire(redisKey, 1, TimeUnit.DAYS);
    }

    public void deleteWaitTaskList(String sn,String taskTypoe) {
        String redisKey = String.format(RBT_WAIT_TASK_LIST,sn,taskTypoe);
        stringRedisTemplate.delete(redisKey);
    }

    public String getPoint(String sn) {
        String redisKey = String.format(RBT_POINT,sn);
        return stringRedisTemplate.opsForValue().get(redisKey);
    }

    public void setPoint(String sn,String point) {
        String redisKey = String.format(RBT_POINT,sn);
        stringRedisTemplate.opsForValue().set(redisKey,point);
    }

    private static String formatTaskKey(String sn) {
        return String.format(RBT_TASK, sn);
    }

    /**
     * 生成序号，使用当前日期，格式为 {PREFIX} + yyyyMMdd + 6 位自增
     * 例如说：202109 000001 （没有中间空格）
     *
     * @return 序号
     */
    public String generateRobotOrderSn() {
        // 递增序号
        String noPrefix = DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATE_PATTERN);
        String key = RedisKeyConstants.RBT_ORDER_SN + noPrefix;
        Long no = stringRedisTemplate.opsForValue().increment(key);
        // 设置过期时间
        stringRedisTemplate.expire(key, Duration.ofDays(1L));
        return noPrefix + String.format("%06d", no);
    }

    /**
     * 生成序号，使用当前日期，格式为 {PREFIX} + yyyyMMdd + 6 位自增
     * 例如说：TK 202109 000001 （没有中间空格）
     *
     * @return 序号
     */
    public String generateTaskNo() {
        // 递增序号
        String noPrefix = TASK_NO_PREFIX + DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATE_PATTERN);
        String key = RedisKeyConstants.RBT_TASK_NO + noPrefix;
        Long no = stringRedisTemplate.opsForValue().increment(key);
        // 设置过期时间
        stringRedisTemplate.expire(key, Duration.ofDays(1L));
        return noPrefix + String.format("%06d", no);
    }

    /**
     * 生成一个新的不重复的4位数字验证码，并存储到Redis
     * @return 生成的验证码
     */
    public synchronized String generateMealCode() {
        String key = getMealCodeKey();
        String code;
        // 循环生成直到获得一个未使用过的验证码
        do {
            code = generateRandomMealCode();
        } while (Boolean.TRUE.equals(stringRedisTemplate.opsForSet().isMember(key, code)));

        // 将验证码添加到集合
        stringRedisTemplate.opsForSet().add(key, code);
        // 设置过期时间（确保24小时后自动删除）
        stringRedisTemplate.expire(key, 1, TimeUnit.DAYS);
        return code;
    }
    /**
     * 验证并删除验证码（一次性使用）
     */
    public boolean validateAndRemoveMealCode(String code) {
        int CODE_LENGTH = 4;
        if (code == null || code.length() != CODE_LENGTH) {
            return false;
        }
        String key = getMealCodeKey();
        // 检查并删除，确保验证码只能使用一次
        Long removed = stringRedisTemplate.opsForSet().remove(key, code);
        return removed != null && removed > 0;
    }

    private String generateRandomMealCode(){
        int code = 1000 + new Random().nextInt(9000);
        return String.valueOf(code);
    }

    private String getMealCodeKey() {
        LocalDate today = LocalDate.now();
        DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        return RBT_MEAL_CODE + today.format(dateFormatter);
    }

}
